package cn.dengta.webapp.base.dao;

import java.io.Serializable;
import java.util.Objects;

import lombok.Getter;
import lombok.Setter;

/**
 * 地理信息类型
 *
 * @author lizhichao
 * @since 2023/3/7
 */
@Setter
@Getter
public class GeoPoint implements Serializable {

	private static final long serialVersionUID = 1L;
	/**
	 * 经度
	 */
	double lon;
	/**
	 * 纬度
	 */
	double lat;

	public GeoPoint(double lon, double lat) {
		this.lon = lon;
		this.lat = lat;
	}

	public GeoPoint(int lonDegrees, int lonMinutes, char lonDirection, int latDegrees, int latMinutes,
	                char latDirection) {
		setLatDms(latDegrees, latMinutes, latDirection);
		setLonDms(lonDegrees, lonMinutes, lonDirection);
	}

	@Override
	public String toString() {
		return "{ lon:" + lon + ",lat:" + lat + "}";
	}

	public String lonToDMS() {
		return decimalToDMS(lon, false);
	}

	public String latToDMS() {
		return decimalToDMS(lat, true);
	}

	public static String decimalToDMS(double decimalValue, boolean isLat) {
		int degrees = (int) decimalValue;
		double minutesAndSeconds = Math.abs((decimalValue - degrees) * 60);
		int minutes = (int) minutesAndSeconds;
		double seconds = (minutesAndSeconds - minutes) * 60;
		char direction = decimalValue >= 0 ? (isLat ? 'E' : 'N') : (isLat ? 'W' : 'S');
		return degrees + "°" + minutes + "'" + seconds + "\"" + direction;
	}

	public static double dmsToDecimal(int degrees, int minutes, boolean isTrue) {
		double decimalValue = Math.abs(degrees) + (double) minutes / 60;
		return isTrue ? decimalValue : -decimalValue;
	}

	public void setLonDms(int degrees, int minutes, char direction) {
		this.lon = dmsToDecimal(degrees, minutes, direction == 'E');
	}

	public void setLatDms(int degrees, int minutes, char direction) {
		this.lat = dmsToDecimal(degrees, minutes, direction == 'N');
	}

	public Character latDirection() {
		return lat > 0 ? 'N' : 'S';
	}

	public Character lonDirection() {
		return lon > 0 ? 'E' : 'W';
	}

	public Integer latDegree() {
		return Math.abs((int) lat);
	}

	public Integer latMinute() {
		int degrees = (int) lat;
		double minutesAndSeconds = Math.abs((lat - degrees) * 60);
		return Math.abs((int) minutesAndSeconds);
	}

	public Integer lonDegree() {
		return Math.abs((int) lon);
	}

	public Integer lonMinute() {
		int degrees = (int) lon;
		double minutesAndSeconds = Math.abs((lon - degrees) * 60);
		return Math.abs((int) minutesAndSeconds);
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o == null || getClass() != o.getClass()) {
			return false;
		}
		GeoPoint geoPoint = (GeoPoint) o;
		return Double.compare(geoPoint.lon, lon) == 0 && Double.compare(geoPoint.lat, lat) == 0;
	}

	@Override
	public int hashCode() {
		return Objects.hash(lon, lat);
	}

}
